<?php

/**
 * mForge Framework
 *
 * LICENSE:
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * The license is bundled with this package in the file LICENSE.txt.
 * You may also obtain a copy of the License at this URL:
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @copyright  Copyright (c) 2011, Jonathan Hedrén
 * @author     Jonathan Hedrén <jonathan.hedren@gmail.com>
 * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
 */

namespace mForge\Modules\Users;

class UserService
{
    /**
     *
     * @var \mForge\Modules\Database\ExtendedPDO
     */
    private $db;

    /**
     *
     * @var string
     */
    private $passwordHashAlgo;
    
    /**
     *
     * @var object
     */
    private $modelClass;

    /**
     *
     * @var string
     */
    private $passwordSalt;
    
    /**
     *
     * @var string
     */
    private $table;

    /**
     *
     * @param \mForge\Modules\Persistence\ExtendedPDO $db
     * @param string $table
     */
    public function __construct(\mForge\Modules\Persistence\ExtendedPDO $db, $table, $passwordHashAlgo, $passwordSalt)
    {
        $this->db = $db;
        $this->table = $table;
        $this->modelClass = __NAMESPACE__ . '\\UserModel';
        $this->passwordHashAlgo = $passwordHashAlgo;
        $this->passwordSalt = $passwordSalt;
    }

    /**
     * Deletes a user
     *
     * @param int $id
     */
    public function delete($id)
    {
        $this->db->delete($this->table, 'id = ?', $id);
    }

    /**
     * Returns all users.
     *
     * @return array
     */
    public function findAll()
    {
        return $this->db->select()
                        ->from($this->table)
                        ->fetchAllAs($this->modelClass);
    }

    /**
     *
     * @param int $id
     * @return UserModel
     */
    public function findById($id)
    {
        return $this->db->select()
                        ->from($this->table)
                        ->where('id = ?')
                        ->bindValues($id)
                        ->fetchAs($this->modelClass);
    }

    /**
     *
     * @param string $username
     * @return UserModel
     */
    public function findByUsername($username)
    {
        return $this->db->select()
                        ->from($this->table)
                        ->where('username = ?')
                        ->bindValues($username)
                        ->fetchAs($this->modelClass);
    }

    /**
     *
     * @param string $email
     * @return UserModel
     */
    public function findByEmail($email)
    {
        return $this->db->select()
                        ->from($this->table)
                        ->where('email = ?')
                        ->bindValues($email)
                        ->fetchAs($this->modelClass);
    }

    /**
     *
     * @param string $password
     * @param string $salt
     * @return string
     */
    public function generatePasswordHash($password)
    {
        return hash($this->passwordHashAlgo, $password . $this->passwordSalt);
    }

    /**
     * Saves a user
     *
     * @param UserModel $model
     * @return UserModel
     */
    public function save(UserModel $model)
    {
        $columnsAndValues = get_object_vars($model);
        // Insert/update the database
        if (empty($model->id)) {
            $result = $this->db->insert($this->table, $columnsAndValues);
            // If we've got no affected rows there is a serious problem.
            if ($result < 1) {
                throw new Exception('The database returned zero affected rows which indicates that no data was saved.');
            }
            $model->id = $this->db->lastInsertId();
        } else {
            $this->db->update($this->table, $columnsAndValues, 'id = ?', $model->id);
        }

        return $model;
    }
}